home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / demo / medit.zip / MAGMAED.CPP < prev    next >
C/C++ Source or Header  |  1994-09-08  |  23KB  |  921 lines

  1. #include "stdafx.h"  // must be in mfc\src\stdafx.h
  2. #include "magmaed.hpp"
  3.  
  4.  
  5. ////////////////////////////////////////////////////////////////////
  6. // CMagmaEdit
  7. //
  8. // This code was taken from the CEdit section of mfc\src\winctrl.cpp
  9. //
  10. ////////////////////////////////////////////////////////////////////
  11. IMPLEMENT_DYNAMIC(CMagmaEdit, CEdit)
  12.  
  13. WNDPROC* CMagmaEdit::GetSuperWndProcAddr()
  14. {
  15.   static WNDPROC NEAR pfnSuper;
  16.   return &pfnSuper;
  17. }
  18.  
  19. BOOL CMagmaEdit::Create(DWORD dwStyle, const RECT& rect, 
  20.                         CWnd* pParentWnd, UINT nID)
  21. {
  22.   return CWnd::Create("MagmaEdit", NULL, dwStyle, rect, pParentWnd, nID);
  23. }
  24.  
  25. CMagmaEdit::~CMagmaEdit()
  26. {
  27.   DestroyWindow();
  28. }
  29.  
  30.  
  31. int CMagmaEdit::GetLastSearchPattern(LPSTR lpBuf)
  32. {
  33.   return (int) ::SendMessage(m_hWnd, ME_QUERYSEARCHSTRING, 0, (LONG) lpBuf);
  34. }
  35.  
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CMagmaEditView
  38.  
  39. IMPLEMENT_DYNCREATE(CMagmaEditView, CView)
  40.  
  41. #define new DEBUG_NEW
  42.  
  43. BEGIN_MESSAGE_MAP(CMagmaEditView, CView)
  44.   //{{AFX_MSG_MAP(CMagmaEditView)
  45.   ON_WM_CREATE()
  46.   ON_WM_PAINT()
  47.   ON_MESSAGE(WM_SETFONT, OnSetFont)
  48.   ON_EN_CHANGE(AFX_IDW_PANE_FIRST, OnEditChange)
  49.   ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
  50.   ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
  51.   ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
  52.   ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
  53.   ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  54.   ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  55.   ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  56.   ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  57.   ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
  58.   ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  59.   ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
  60.   ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
  61.   ON_COMMAND(ID_EDIT_FIND, OnEditFind)
  62.   ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
  63.   ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
  64.   ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
  65.   ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
  66.   ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
  67.  
  68.   ON_COMMAND(ID_EDIT_MARKLINE, OnEditMarkLine)
  69.   ON_COMMAND(ID_EDIT_MARKLINERANGE, OnEditMarkLineRange)
  70.   ON_COMMAND(ID_EDIT_STREAMMARK, OnEditMarkStream)
  71.   ON_COMMAND(ID_EDIT_RECTMARK, OnEditMarkRect)
  72.   ON_COMMAND(ID_EDIT_RESETMARK, OnEditMarkReset)
  73.  
  74.   //}}AFX_MSG_MAP
  75.  
  76. // Standard Print commands (print only - not preview)
  77. ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  78. END_MESSAGE_MAP()
  79.  
  80. const DWORD CMagmaEditView::dwStyleDefault =
  81.     AFX_WS_DEFAULT_VIEW |
  82.     WS_HSCROLL | WS_VSCROLL |
  83.     ES_AUTOHSCROLL | ES_AUTOVSCROLL |
  84.     ES_MULTILINE | ES_NOHIDESEL;
  85.  
  86. // Operating system specific maximum buffer limit
  87. const DWORD CMagmaEditView::nMaxSize = 0x7FFFFFFFL;
  88.  
  89. // class name for control creation
  90. static char BASED_CODE szClassName[] = "MagmaEdit";
  91.  
  92. #ifdef USE_VBX
  93. static HMODULE hMagmaEditModule = NULL;
  94. #else
  95. static HMODULE hMagmaEditModule = ::LoadLibrary("magmaed.dll");
  96. #endif
  97.  
  98. static HMODULE hBWCCModule = ::LoadLibrary("bwcc.dll");
  99.  
  100. /////////////////////////////////////////////////////////////////////////////
  101. // CMagmaEditView construction/destruction
  102.  
  103. CMagmaEditView::CMagmaEditView()
  104. {
  105. #ifdef USE_VBX
  106.   if (hMagmaEditModule == NULL)
  107.   {
  108.     hMagmaEditModule = AfxGetApp()->LoadVBXFile("magmaed.vbx");
  109.     ASSERT(hMagmaEditModule > (HMODULE) 32);
  110.     AfxGetApp()->UnloadVBXFile("magmaed.vbx");
  111.   }
  112. #endif
  113.  
  114.   ASSERT(hMagmaEditModule > (HMODULE) 32);
  115.   ASSERT(hBWCCModule > (HMODULE) 32);
  116.  
  117.   m_nTabStops    = 8*4;  // default 8 character positions
  118.   m_hPrinterFont = NULL;
  119.   m_hMirrorFont  = NULL;
  120. }
  121.  
  122. CMagmaEditView::~CMagmaEditView()
  123. {
  124.   ASSERT(m_hWnd == NULL);
  125.   ASSERT(hMagmaEditModule > (HMODULE) 32);
  126. //::FreeLibrary(hMagmaEditModule);
  127. }
  128.  
  129. WNDPROC* CMagmaEditView::GetSuperWndProcAddr()
  130. {
  131.   static WNDPROC NEAR pfnSuper;
  132.   return &pfnSuper;
  133. }
  134.  
  135. //
  136. // How does a CMagmaEdit window get associated with CMagmaEditView?
  137. //
  138. // When the CMagmaEditView is created, it calls CWnd::CreateWindowEx
  139. // in order to create the child inside the view. CreateWindowEx creates
  140. // a CREATESTRUCT data structure with lpszClass set to NULL. It then
  141. // calls CMagmaEditView::PreCreateWindow. In PreCreateWindow, we set the
  142. // cs.lpszClass to "MagmaEdit", the class name of the child window we want
  143. // to create. CreateWindowEx then proceed to create the CMagmaEdit window.
  144. //
  145. BOOL CMagmaEditView::PreCreateWindow(CREATESTRUCT& cs)
  146. {
  147.   ASSERT(cs.lpszClass == NULL);
  148.   cs.lpszClass = szClassName;
  149.  
  150.   // map default CView style to default CMagmaEditView style
  151.   if (cs.style == AFX_WS_DEFAULT_VIEW)
  152.     cs.style = dwStyleDefault;
  153.  
  154.   return TRUE;
  155. }
  156.  
  157. int CMagmaEditView::OnCreate(LPCREATESTRUCT lpcs)
  158. {
  159.   if (CView::OnCreate(lpcs) != 0)
  160.     return -1;
  161.   //
  162.   // MODIFICATION : We should change LimitText so it takes a DWORD
  163.   //
  164.   GetEditCtrl().LimitText((UINT) nMaxSize);
  165.   GetEditCtrl().SetTabStops(m_nTabStops);
  166.   
  167.   HFONT hFont = (HFONT) ::SendMessage(GetEditCtrl().m_hWnd, WM_GETFONT, 0, 0L);
  168.   LOGFONT lf;
  169.   ::GetObject(hFont, sizeof(lf), &lf);
  170.   m_font.CreateFontIndirect(&lf);
  171.   SetFont(&m_font);
  172.  
  173.   return 0;
  174. }
  175.  
  176. // EDIT controls always turn off WS_BORDER and draw it themselves
  177. #define CX_BORDER  1
  178. #define CY_BORDER  1
  179.  
  180. void CMagmaEditView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  181. {
  182.   if (nAdjustType != 0)
  183.   {
  184.     // default behavior for in-place editing handles scrollbars
  185.     DWORD dwStyle = GetStyle();
  186.     if (dwStyle & WS_VSCROLL)
  187.       lpClientRect->right += ::GetSystemMetrics(SM_CXVSCROLL) - CX_BORDER;
  188.     if (dwStyle & WS_HSCROLL)
  189.       lpClientRect->bottom += ::GetSystemMetrics(SM_CYHSCROLL) - CY_BORDER;
  190.     return;
  191.   }
  192.  
  193.   ::AdjustWindowRect(lpClientRect, GetStyle() | WS_BORDER, FALSE);
  194. }
  195.  
  196. /////////////////////////////////////////////////////////////////////////////
  197. // CMagmaEditView document like functions
  198.  
  199. void CMagmaEditView::DeleteContents()
  200. {
  201.   ASSERT_VALID(this);
  202.   ASSERT(m_hWnd != NULL);
  203.   SetWindowText(NULL);
  204.   ASSERT_VALID(this);
  205. }
  206.  
  207. void CMagmaEditView::Serialize(CArchive& ar)
  208.   // Read and write CMagmaEditView object to archive, with length prefix.
  209. {
  210.   ASSERT_VALID(this);
  211.   ASSERT(m_hWnd != NULL);
  212.   if (ar.IsStoring())
  213.   {
  214.     DWORD nLen = GetBufferLength();
  215.     ar << nLen;
  216.     WriteToArchive(ar);
  217.   }
  218.   else
  219.   {
  220.     DWORD dwLen;
  221.     ar >> dwLen;
  222.     if (dwLen > nMaxSize)
  223.     {
  224.       AfxThrowArchiveException(CArchiveException::badIndex);
  225.       ASSERT(FALSE);
  226.     }
  227.     ReadFromArchive(ar, dwLen);
  228.   }
  229.   ASSERT_VALID(this);
  230. }
  231.  
  232. void CMagmaEditView::ReadFromArchive(CArchive& ar, DWORD nLen)
  233. // Read certain amount of text from the file, assume at least nLen
  234. // bytes are in the file.
  235. {
  236.   (void) nLen;
  237.  
  238.   ASSERT_VALID(this);
  239.  
  240.   ::SendMessage(GetEditCtrl().m_hWnd, ME_OPENFILE, ar.GetFile()->m_hFile, 0L);
  241.  
  242.   Invalidate();
  243.   ASSERT_VALID(this);
  244. }
  245.  
  246. void CMagmaEditView::WriteToArchive(CArchive& ar)
  247. // Write just the text to an archive, no length prefix.
  248. {
  249.   ASSERT_VALID(this);
  250.  
  251.   TRY
  252.   {
  253.     ::SendMessage(GetEditCtrl().m_hWnd, ME_WRITEFILE, ar.GetFile()->m_hFile, 0L);
  254.   }
  255.   CATCH_ALL(e)
  256.   {
  257.     THROW_LAST();
  258.     ASSERT(FALSE);
  259.   }
  260.   END_CATCH_ALL
  261.  
  262.   ASSERT_VALID(this);
  263. }
  264.  
  265. void CMagmaEditView::SerializeRaw(CArchive& ar)
  266. // Read/Write object as stand-alone file.
  267. {
  268.   ASSERT_VALID(this);
  269.   if (ar.IsStoring())
  270.   {
  271.     WriteToArchive(ar);
  272.   }
  273.   else  // reading from a file
  274.   {
  275.     CFile* pFile = ar.GetFile();
  276.     ASSERT(pFile->GetPosition() == 0);
  277.     DWORD nFileSize = pFile->GetLength();
  278.     // Make sure that the file isn't larger than what the buffer can hold
  279.     if (nFileSize > nMaxSize)
  280.     {
  281.       AfxMessageBox(AFX_IDP_FILE_TOO_LARGE);
  282.       AfxThrowUserException();
  283.       ASSERT(FALSE);
  284.     }
  285.     ReadFromArchive(ar, nFileSize);
  286.   }
  287.   ASSERT_VALID(this);
  288. }
  289.  
  290. /////////////////////////////////////////////////////////////////////////////
  291. // CMagmaEditView drawing
  292.  
  293. void CMagmaEditView::OnPaint()
  294. {
  295.   // do not call CView::OnPaint since it will call OnDraw
  296.   CWnd::OnPaint();
  297. }
  298.  
  299. void CMagmaEditView::OnDraw(CDC*)
  300. {
  301.   // do nothing here since CWnd::OnPaint() will repaint the EDIT control
  302. }
  303.  
  304. /////////////////////////////////////////////////////////////////////////////
  305. // CMagmaEditView commands
  306.  
  307. void CMagmaEditView::OnUpdateNeedSel(CCmdUI* pCmdUI)
  308. {
  309.   //
  310.   // Checks to see if there is any selected text in the buffer
  311.   //
  312.   // MODIFICATION : Add check for line marks
  313.   //
  314.   ASSERT_VALID(this);
  315.  
  316. #if 0
  317.   //
  318.   // Ifdef'ed out.. we should always be able to cut
  319.   //
  320.   int nStartChar, nEndChar;
  321.   GetEditCtrl().GetSel(nStartChar, nEndChar);
  322.   pCmdUI->Enable(nStartChar != nEndChar);
  323. #else
  324.   pCmdUI->Enable(TRUE);
  325. #endif
  326.  
  327.   ASSERT_VALID(this);
  328. }
  329.  
  330.  
  331. void CMagmaEditView::OnUpdateNeedClip(CCmdUI* pCmdUI)
  332. {
  333.   //
  334.   // Checks to see if there is text waiting in the clipboard. If so,
  335.   // the Paste menu item is enabled.
  336.   //
  337.   ASSERT_VALID(this);
  338.   pCmdUI->Enable(::IsClipboardFormatAvailable(CF_TEXT));
  339.   ASSERT_VALID(this);
  340. }
  341.  
  342.  
  343. void CMagmaEditView::OnUpdateNeedText(CCmdUI* pCmdUI)
  344. {
  345.   ASSERT_VALID(this);
  346.   pCmdUI->Enable(GetBufferLength() != 0);
  347.   ASSERT_VALID(this);
  348. }
  349.  
  350.  
  351. void CMagmaEditView::OnUpdateEditUndo(CCmdUI* pCmdUI)
  352. {
  353.   ASSERT_VALID(this);
  354.   //
  355.   // Checks to see if anything is in the UNDO stack
  356.   //
  357.   pCmdUI->Enable(GetEditCtrl().CanUndo());
  358.   ASSERT_VALID(this);
  359. }
  360.  
  361.  
  362. void CMagmaEditView::OnEditChange()
  363. {
  364.   ASSERT_VALID(this);
  365.   GetDocument()->SetModifiedFlag();
  366.   ASSERT_VALID(this);
  367. }
  368.  
  369.  
  370. void CMagmaEditView::OnEditCut()
  371. {
  372.   ASSERT_VALID(this);
  373.   GetEditCtrl().Cut();
  374.   ASSERT_VALID(this);
  375. }
  376.  
  377.  
  378. void CMagmaEditView::OnEditCopy()
  379. {
  380.   ASSERT_VALID(this);
  381.   GetEditCtrl().Copy();
  382.   ASSERT_VALID(this);
  383. }
  384.  
  385.  
  386. void CMagmaEditView::OnEditPaste()
  387. {
  388.   ASSERT_VALID(this);
  389.   GetEditCtrl().Paste();
  390.   ASSERT_VALID(this);
  391. }
  392.  
  393.  
  394. void CMagmaEditView::OnEditClear()
  395. {
  396.   ASSERT_VALID(this);
  397.   GetEditCtrl().Clear();
  398.   ASSERT_VALID(this);
  399. }
  400.  
  401.  
  402. void CMagmaEditView::OnEditUndo()
  403. {
  404.   ASSERT_VALID(this);
  405.   GetEditCtrl().Undo();
  406.   ASSERT_VALID(this);
  407. }
  408.  
  409.  
  410. void CMagmaEditView::OnEditSelectAll()
  411. {
  412.   ASSERT_VALID(this);
  413.   //
  414.   // Select everything in the buffer
  415.   //
  416.   GetEditCtrl().SetSel(0, -1);
  417.   ASSERT_VALID(this);
  418. }
  419.  
  420.  
  421. void CMagmaEditView::OnEditMarkLine()
  422. {
  423.   ASSERT_VALID(this);
  424.   ::SendMessage(GetEditCtrl().m_hWnd, ME_MARKLINE, 0, 0L);
  425.   ASSERT_VALID(this);
  426. }
  427. void CMagmaEditView::OnEditMarkLineRange()
  428. {
  429.   ASSERT_VALID(this);
  430.   ::SendMessage(GetEditCtrl().m_hWnd, ME_MARKLINERANGE, 0, 0L);
  431.   ASSERT_VALID(this);
  432. }
  433. void CMagmaEditView::OnEditMarkStream()
  434. {
  435.   ASSERT_VALID(this);
  436.   ::SendMessage(GetEditCtrl().m_hWnd, ME_STREAMMARK, 0, 0L);
  437.   ASSERT_VALID(this);
  438. }
  439. void CMagmaEditView::OnEditMarkRect()
  440. {
  441.   ASSERT_VALID(this);
  442.   ::SendMessage(GetEditCtrl().m_hWnd, ME_RECTMARK, 0, 0L);
  443.   ASSERT_VALID(this);
  444. }
  445. void CMagmaEditView::OnEditMarkReset()
  446. {
  447.   ASSERT_VALID(this);
  448.   ::SendMessage(GetEditCtrl().m_hWnd, ME_RESETMARK, 0, 0L);
  449.   ASSERT_VALID(this);
  450. }
  451.  
  452.  
  453. /////////////////////////////////////////////////////////////////////////////
  454. // CMagmaEditView Font Handling
  455.  
  456. LRESULT CMagmaEditView::OnSetFont(WPARAM wParam, LPARAM lParam)
  457. {
  458.   ASSERT_VALID(this);
  459.   Default();
  460.   GetEditCtrl().SetTabStops(m_nTabStops);
  461.   ASSERT_VALID(this);
  462.   return 0;
  463. }
  464.  
  465. void CMagmaEditView::SetPrinterFont(CFont* pFont)
  466. {
  467.   ASSERT_VALID(this);
  468.   m_hPrinterFont = (HFONT)pFont->GetSafeHandle();
  469.   ASSERT_VALID(this);
  470. }
  471.  
  472. CFont* CMagmaEditView::GetPrinterFont() const
  473. {
  474.   ASSERT_VALID(this);
  475.   return CFont::FromHandle(m_hPrinterFont);
  476. }
  477.  
  478. /////////////////////////////////////////////////////////////////////////////
  479. // CMagmaEditView attributes
  480.  
  481. DWORD CMagmaEditView::GetBufferLength() const
  482. {
  483.   ASSERT_VALID(this);
  484.   ASSERT(m_hWnd != NULL);
  485.   DWORD nLen = GetWindowTextLength();
  486.   return nLen;
  487. }
  488.  
  489. /////////////////////////////////////////////////////////////////////////////
  490. // CMagmaEditView Find & Replace
  491.  
  492. void CMagmaEditView::OnUpdateNeedFind(CCmdUI* pCmdUI)
  493. {
  494.   ASSERT_VALID(this);
  495.  
  496.   //
  497.   // Checks to see if there is a previous search pattern
  498.   //
  499.   // MODIFICATION : Use a MagmaEdit message to query the previous
  500.   //                search string
  501.   //                     GetEditCtrl().GetLastSearchPattern() > 0
  502.   //
  503.   //
  504.   pCmdUI->Enable(GetBufferLength() != 0 &&
  505.                  GetEditCtrl().GetLastSearchPattern() > 0);
  506.  
  507.   ASSERT_VALID(this);
  508. }
  509.  
  510.  
  511. void CMagmaEditView::OnEditFind()
  512. {
  513.   ASSERT_VALID(this);
  514.   OnEditFindReplace(TRUE);
  515.   ASSERT_VALID(this);
  516. }
  517.  
  518. void CMagmaEditView::OnEditReplace()
  519. {
  520.   ASSERT_VALID(this);
  521.   OnEditFindReplace(FALSE);
  522.   ASSERT_VALID(this);
  523. }
  524.  
  525. void CMagmaEditView::OnEditRepeat()
  526. {
  527.   ASSERT_VALID(this);
  528.   if (::SendMessage(GetEditCtrl().m_hWnd, ME_SEARCHAGAIN, 0, 0L) == 0)
  529.     OnTextNotFound();
  530. }
  531.  
  532. void CMagmaEditView::OnEditFindReplace(BOOL bFindOnly)
  533. {
  534.   ASSERT_VALID(this);
  535.   if (::SendMessage(GetEditCtrl().m_hWnd,
  536.                     (bFindOnly) ? ME_FSEARCH : ME_FREPLACE,
  537.                     0,
  538.                     0L) == 0)
  539.     OnTextNotFound();
  540. }
  541.  
  542. void CMagmaEditView::OnFindNext(LPCSTR lpszFind, BOOL bNext, BOOL bCase)
  543. {
  544.   ASSERT_VALID(this);
  545. }
  546.  
  547. void CMagmaEditView::OnReplaceSel(LPCSTR lpszFind, BOOL bNext, BOOL bCase,
  548.                                   LPCSTR lpszReplace)
  549. {
  550.   ASSERT_VALID(this);
  551. }
  552.  
  553. void CMagmaEditView::OnReplaceAll(LPCSTR lpszFind, LPCSTR lpszReplace, 
  554.                                   BOOL bCase)
  555. {
  556.   ASSERT_VALID(this);
  557. }
  558.  
  559. LRESULT CMagmaEditView::OnFindReplaceCmd(WPARAM, LPARAM lParam)
  560. {
  561.   ASSERT_VALID(this);
  562.   return 0;
  563. }
  564.  
  565. void CMagmaEditView::OnTextNotFound(LPCSTR)
  566. {
  567.   ASSERT_VALID(this);
  568.   MessageBeep(0);
  569. }
  570.  
  571.  
  572. /////////////////////////////////////////////////////////////////////////////
  573. // CMagmaEditView Tab Stops
  574.  
  575. void CMagmaEditView::SetTabStops(int nTabStops)
  576. {
  577.   ASSERT_VALID(this);
  578.   m_nTabStops = nTabStops;
  579.   GetEditCtrl().SetTabStops(m_nTabStops);
  580.   Invalidate();
  581.   ASSERT_VALID(this);
  582. }
  583.  
  584. /////////////////////////////////////////////////////////////////////////////
  585. // CMagmaEditView diagnostics
  586.  
  587. #ifdef _DEBUG
  588. void CMagmaEditView::AssertValid() const
  589. {
  590.   CView::AssertValid();
  591.   ASSERT_VALID(&m_aPageStart);
  592.  
  593.   if (m_hPrinterFont != NULL)
  594.     ASSERT_VALID(CFont::FromHandle(m_hPrinterFont));
  595.  
  596.   if (m_hMirrorFont != NULL)
  597.     ASSERT_VALID(CFont::FromHandle(m_hMirrorFont));
  598. }
  599.  
  600. void CMagmaEditView::Dump(CDumpContext& dc) const
  601. {
  602.   CView::Dump(dc);
  603.   AFX_DUMP1(dc, "\nm_nTabStops = ", m_nTabStops);
  604.   if (m_hPrinterFont != NULL)
  605.     AFX_DUMP1(dc, "\nm_hPrinterFont ", (UINT)m_hPrinterFont);
  606.   if (m_hMirrorFont != NULL)
  607.     AFX_DUMP1(dc, "\nm_hMirrorFont ", (UINT)m_hMirrorFont);
  608.   AFX_DUMP1(dc, "\nm_aPageStart ", &m_aPageStart);
  609. }
  610. #endif //_DEBUG
  611.  
  612. /////////////////////////////////////////////////////////////////////////////
  613.  
  614. static UINT NEAR PASCAL
  615. ClipLine(CDC* pDC, int aCharWidths[256], int cxLine, int nTabStop, 
  616.          LPCSTR lpszText, UINT nChars)
  617. {
  618.   ASSERT_VALID(pDC);
  619.  
  620.   TEXTMETRIC tm;
  621.   pDC->GetTextMetrics(&tm);
  622.  
  623.   // make an initial guess on the number of characters that will fit
  624.   int cx = 0;
  625.   LPCSTR lpszStart = lpszText;
  626.   LPCSTR lpszStop = lpszText + nChars;
  627.   LPCSTR lpsz = lpszStart;
  628.   while (lpsz < lpszStop)
  629.   {
  630.     if (*lpsz == '\t')
  631.       cx += nTabStop - (cx % nTabStop);
  632.     else
  633.     {
  634. #ifdef AFXDATA_DEFINED
  635.       if (afxData.bDBCS && _AfxIsDBCSLeadByte(*lpsz))
  636.       {
  637.         ++lpsz;
  638.         cx += tm.tmAveCharWidth;
  639.       }
  640.       else
  641. #endif
  642.         cx += aCharWidths[(BYTE)*lpsz];
  643.     }
  644.     ++lpsz;
  645.     if (cx > cxLine)
  646.       break;
  647.   }
  648.  
  649.   // adjust for errors in the guess
  650.   cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  651.   if (cx > cxLine)
  652.   {
  653.     // remove characters until it fits
  654.     do
  655.     {
  656.       ASSERT(lpsz != lpszStart);
  657. #ifdef AFXDATA_DEFINED
  658.       if (afxData.bDBCS)
  659.         lpsz = AnsiPrev(lpszStart, lpsz);
  660.       else
  661. #endif
  662.         --lpsz;
  663.       cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  664.     } while (cx > cxLine);
  665.   }
  666.   else if (cx < cxLine)
  667.   {
  668.     // add characters until it doesn't fit
  669.     while (lpsz < lpszStop)
  670.     {
  671.       lpsz = AnsiNext(lpsz);
  672.       ASSERT(lpsz <= lpszStop);
  673.       cx = pDC->GetTabbedTextExtent(lpszStart, lpsz-lpszStart, 1, &nTabStop).cx;
  674.       if (cx > cxLine)
  675.       {
  676. #ifdef AFXDATA_DEFINED
  677.         if (afxData.bDBCS)
  678.           lpsz = AnsiPrev(lpszStart, lpsz);
  679.         else
  680. #endif
  681.           --lpsz;
  682.         break;
  683.       }
  684.     }
  685.   }
  686.  
  687.   // return index of character just past the last that would fit
  688.   return lpsz - lpszText;
  689. }
  690.  
  691.  
  692. UINT   // returns the line # which starts the next page
  693. CMagmaEditView::PrintInsideRect(CDC* pDC, RECT& rectLayout,
  694.   UINT nLineStart,  // this is the 0-based starting line
  695.   UINT nLineStop)   // this is the 0-based ending line
  696.   // worker function for laying out text in a rectangle.
  697. {
  698.   ASSERT_VALID(this);
  699.   ASSERT_VALID(pDC);
  700.  
  701.   // get buffer and real starting and ending postions
  702.   UINT nLines = GetEditCtrl().GetLineCount();
  703.   if (nLineStart >= nLines)
  704.     return nLines;
  705.  
  706.   LPSTR lpszText = new char[2048];
  707.  
  708.   if (nLineStop > nLines)
  709.     nLineStop = nLines;
  710.   ASSERT(nLineStart < nLines);
  711.  
  712.   // calculate text & tab metrics
  713.   TEXTMETRIC tm;
  714.   pDC->GetTextMetrics(&tm);
  715.   int cyChar = tm.tmHeight;
  716.   int nTabStop = m_nTabStops*pDC->GetTabbedTextExtent("\t",1,0,NULL).cx / 8 / 4;
  717.   int aCharWidths[256];
  718.   pDC->GetCharWidth(0, 255, aCharWidths);
  719.  
  720.   int y = rectLayout.top;
  721.   UINT cx = rectLayout.right - rectLayout.left;
  722.  
  723.   VERIFY(pDC->SaveDC() != 0);
  724.   BOOL bLayoutOnly = pDC->IntersectClipRect(&rectLayout) == NULLREGION;
  725.  
  726.   do
  727.   {
  728.     // Get the current line into lpszBuffer
  729.     GetEditCtrl().GetLine(nLineStart, lpszText, 2048);
  730.     UINT nChars = lstrlen(lpszText);
  731.  
  732.     if (nChars == 0)
  733.     {
  734.       y += cyChar;
  735.     }
  736.     else
  737.     {
  738.       // non-word wrap printing (much easier and faster)
  739.       CRect rect(rectLayout.left, y, rectLayout.right, y+cyChar);
  740.       if (!bLayoutOnly && pDC->RectVisible(rect))
  741.       {
  742.         UINT nIndexClip = ClipLine(pDC, aCharWidths, cx, nTabStop,
  743.           lpszText, nChars);
  744.         if (nIndexClip < nChars)
  745.         {
  746. #ifdef AFXDATA_DEFINED
  747.           if (_AfxIsDBCSLeadByte(*(lpszText+nIndexClip)))
  748.             nIndexClip++;
  749. #endif
  750.           nIndexClip++;
  751.         }
  752.         pDC->TabbedTextOut(rect.left, y,
  753.           (LPCSTR)lpszText, nIndexClip, 1,
  754.           &nTabStop, rect.left);
  755.       }
  756.       y += cyChar;
  757.     }
  758.     nLineStart++;
  759.   }
  760.   while (nLineStart < nLineStop && y+cyChar <= rectLayout.bottom);
  761.  
  762.   VERIFY(pDC->RestoreDC(-1));
  763.   ASSERT_VALID(this);
  764.  
  765.   rectLayout.bottom = y;
  766.   return nLineStart;
  767. }
  768.  
  769.  
  770. /////////////////////////////////////////////////////////////////////////////
  771. // CMagmaEditView Printing support
  772.  
  773. BOOL CMagmaEditView::OnPreparePrinting(CPrintInfo* pInfo)
  774. {
  775.   return DoPreparePrinting(pInfo);
  776. }
  777.  
  778. void CMagmaEditView::OnBeginPrinting(CDC* pDC, CPrintInfo*)
  779. {
  780.   ASSERT_VALID(this);
  781.   ASSERT_VALID(pDC);
  782.   // initialize page start vector
  783.   ASSERT(m_aPageStart.GetSize() == 0);
  784.   m_aPageStart.Add(0);
  785.   ASSERT(m_aPageStart.GetSize() > 0);
  786.  
  787.   if (m_hPrinterFont == NULL)
  788.   {
  789.     // get current screen font object metrics
  790.     CFont* pFont = GetFont();
  791.     LOGFONT lf;
  792.     if (pFont == NULL)
  793.       return;
  794.     pFont->GetObject(sizeof(LOGFONT), &lf);
  795.     static char BASED_CODE szSystem[] = "system";
  796.     if (lstrcmpi((LPCSTR)lf.lfFaceName, szSystem) == 0)
  797.       return;
  798.  
  799.     // map to printer font metrics
  800.     HDC hDCFrom = ::GetDC(NULL);
  801.     lf.lfHeight = ::MulDiv(lf.lfHeight, pDC->GetDeviceCaps(LOGPIXELSY),
  802.       ::GetDeviceCaps(hDCFrom, LOGPIXELSY));
  803.     lf.lfWidth = ::MulDiv(lf.lfWidth, pDC->GetDeviceCaps(LOGPIXELSX),
  804.       ::GetDeviceCaps(hDCFrom, LOGPIXELSX));
  805.     ::ReleaseDC(NULL, hDCFrom);
  806.  
  807.     //
  808.     // MagmaEd uses an OEM_CHARSET screen font. However, for our
  809.     // HP LaserJet, Windows maps this font into a SCRIPT printer font.
  810.     // So, in order to get a normal font, we must set the lfCharSet to 
  811.     // DEFAULT_CHARSET.
  812.     //
  813.     lf.lfCharSet = DEFAULT_CHARSET;
  814.  
  815.     // create it, if it fails we just the the printer's default.
  816.     m_hMirrorFont = ::CreateFontIndirect(&lf);
  817.     m_hPrinterFont = m_hMirrorFont;
  818.   }
  819.   ASSERT_VALID(this);
  820. }
  821.  
  822. BOOL CMagmaEditView::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
  823.   // attempts pagination to pInfo->m_nCurPage, TRUE == success
  824. {
  825.   ASSERT_VALID(this);
  826.   ASSERT_VALID(pDC);
  827.  
  828.   CRect rectSave = pInfo->m_rectDraw;
  829.   UINT nPageSave = pInfo->m_nCurPage;
  830.   ASSERT(nPageSave > 1);
  831.   ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
  832.   VERIFY(pDC->SaveDC() != 0);
  833.   pDC->IntersectClipRect(0, 0, 0, 0);
  834.   pInfo->m_nCurPage = m_aPageStart.GetSize();
  835.   while (pInfo->m_nCurPage < nPageSave)
  836.   {
  837.     ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
  838.     OnPrepareDC(pDC, pInfo);
  839.     ASSERT(pInfo->m_bContinuePrinting);
  840.     pInfo->m_rectDraw.SetRect(0, 0,
  841.       pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  842.     pDC->DPtoLP(&pInfo->m_rectDraw);
  843.     OnPrint(pDC, pInfo);
  844.     if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
  845.       break;
  846.     ++pInfo->m_nCurPage;
  847.   }
  848.   BOOL bResult = pInfo->m_nCurPage == nPageSave;
  849.   VERIFY(pDC->RestoreDC(-1));
  850.   pInfo->m_nCurPage = nPageSave;
  851.   pInfo->m_rectDraw = rectSave;
  852.   ASSERT_VALID(this);
  853.   return bResult;
  854. }
  855.  
  856. void CMagmaEditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  857. {
  858.   ASSERT_VALID(this);
  859.   ASSERT_VALID(pDC);
  860.   ASSERT(pInfo != NULL);  // overriding OnPaint -- never get this.
  861.  
  862.   if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
  863.     !PaginateTo(pDC, pInfo))
  864.   {
  865.     // can't paginate to that page, thus cannot print it.
  866.     pInfo->m_bContinuePrinting = FALSE;
  867.   }
  868.   ASSERT_VALID(this);
  869. }
  870.  
  871. void CMagmaEditView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
  872. {
  873.   ASSERT_VALID(this);
  874.   ASSERT_VALID(pDC);
  875.   ASSERT(pInfo != NULL);
  876.   ASSERT(pInfo->m_bContinuePrinting);
  877.  
  878.   CFont* pOldFont = NULL;
  879.   if (m_hPrinterFont != NULL)
  880.     pOldFont = pDC->SelectObject(CFont::FromHandle(m_hPrinterFont));
  881.   pDC->SetBkMode(TRANSPARENT);
  882.  
  883.   UINT nPage = pInfo->m_nCurPage;
  884.   ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
  885.   UINT nIndex = m_aPageStart[nPage-1];
  886.  
  887.   // print as much as possible in the current page.
  888.   nIndex = PrintInsideRect(pDC, pInfo->m_rectDraw, nIndex, 0xFFFF);
  889.  
  890.   if (pOldFont != NULL)
  891.     pDC->SelectObject(pOldFont);
  892.  
  893.   // update pagination information for page just printed
  894.   if (nPage == (UINT)m_aPageStart.GetSize())
  895.   {
  896.     if (nIndex < (UINT) GetEditCtrl().GetLineCount())
  897.       m_aPageStart.Add(nIndex);
  898.   }
  899.   else
  900.   {
  901.     ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
  902.     ASSERT(nIndex == m_aPageStart[nPage+1-1]);
  903.   }
  904. }
  905.  
  906. void CMagmaEditView::OnEndPrinting(CDC*, CPrintInfo*)
  907. {
  908.   ASSERT_VALID(this);
  909.  
  910.   m_aPageStart.RemoveAll();
  911.   if (m_hMirrorFont != NULL && m_hPrinterFont == m_hMirrorFont)
  912.   {
  913.     ::DeleteObject(m_hMirrorFont);
  914.     m_hMirrorFont = NULL;
  915.     m_hPrinterFont = NULL;
  916.   }
  917. }
  918.  
  919.  
  920.  
  921.